from core.config import cfg
from django.utils.timezone import datetime, timedelta
from core.cache import WEB_CACHE
from core.log import logging
from TDhelper.generic.crypto.MD5 import MD5


class Token_Cache:
    __document__ = "token"

    @classmethod
    def auto_generate_token(cls, expire, event, union_field=None, sys_key=cfg.SERVICE_KEY, remote_ip=None, hash_str=None):
        """
        @classmethod
        自动生成并添加token到缓存
        
        Args:
            expire: token过期时间
            event: 关联事件标识
            union_field: 可选联合字段，默认为空
            sys_key: 系统密钥，默认为配置的服务密钥
            remote_ip: 可选远程IP，默认为空
            hash_str: 可选哈希字符串，默认为当前时间
        
        Returns:
            生成的token字符串
        
        根据提供的参数生成MD5 token，并将其添加到token缓存中。
        token由过期时间、事件、联合字段、系统密钥、远程IP和哈希字符串(或当前时间)组合生成。
        """
        token = MD5([str(expire), event, union_field if union_field else "",
                    sys_key, remote_ip if remote_ip else "", hash_str if hash_str else datetime.now().strftime("%Y-%m-%d %H:%M:%S"), datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
        return cls.add_token(token, expire=expire, event=event, union_field=union_field, sys_key=sys_key, remote_ip=remote_ip,use_once=0,is_use=0)

    @classmethod
    def add_token(cls, token, expire, event, union_field=None, sys_key=cfg.SERVICE_KEY, remote_ip=None,use_once=0,is_use=0):
        """添加token到缓存
                
                参数:
                    token: 需要缓存的token字符串
                    expire: token过期时间
                    event: token关联的事件类型
                    union_field: 关联字段(可选)
                    sys_key: 系统标识(默认使用配置中的SERVICE_KEY)
                    remote_ip: 远程IP地址(可选)
                    use_once: 是否一次性使用(0/1)
                    is_use: 是否已使用(0/1)
                    
                返回:
                    tuple: (操作状态, 操作结果) 
                          操作状态为True表示成功，False表示失败
                          操作结果为缓存操作返回的对象
        """
        try:
            # 后续加根据union_field,sys_key删除其他TOKEN保证当前用户仅有一个TOKEN在库
            if remote_ip:
                WEB_CACHE.collect(cls.__document__).remove(
                        **{"union_field": union_field, "event": event, "sys_key": sys_key, "remote_ip": remote_ip,"use_once":use_once,"is_use":is_use})
            else:
                WEB_CACHE.collect(cls.__document__).remove(
                        **{"union_field": union_field, "event": event, "sys_key": sys_key,"use_once":use_once,"is_use":is_use})
        except:
            pass
        token = MD5(
                [token, event, sys_key, datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
        return True, WEB_CACHE.collect(cls.__document__).set(**{"token": token, "expire": expire, "sys_key": sys_key, "union_field": union_field, "event": event, "remote_ip": remote_ip,"use_once":0,"is_use":0})
        

    @classmethod
    def validate_token(cls, token, event=None, sys_key=cfg.SERVICE_KEY, remote_ip=None, auto_renewal=False):
        """
        验证并管理token的有效性
        
        @classmethod
        @param token: 需要验证的token字符串
        @param event: 可选，关联的事件标识
        @param sys_key: 可选，系统密钥，默认为配置中的SERVICE_KEY
        @param remote_ip: 可选，远程IP地址
        @param auto_renewal: 可选，是否自动续期token，默认为False
        @return: 元组(验证结果, 结果信息/错误信息)
                 验证成功返回(True, token详情字典)
                 验证失败返回(False, 错误原因字符串/异常对象)
        @note: 1. 自动续期仅在token有效期剩余20%时触发
               2. 一次性token(is_use=1)使用后会自动标记为已使用
               3. 过期token会自动删除
        """
        try:
            if remote_ip:
                result = WEB_CACHE.collect(cls.__document__).get(
                    **{"token": token, "sys_key": sys_key, "event": event, "remote_ip": remote_ip})
            else:
                result = WEB_CACHE.collect(cls.__document__).get(
                    **{"token": token, "sys_key": sys_key, "event": event})
            if result:
                if result['use_once']==0:
                    if result['expire'] > datetime.now():
                        if auto_renewal:
                            if result['expire'].__add__(timedelta(seconds=cfg.TOKEN_EXPIRE_TIME*0.2)) > datetime.now():
                                try:
                                    result['expire'] = datetime.now().__add__(
                                        timedelta(seconds=cfg.TOKEN_EXPIRE_TIME))
                                    WEB_CACHE.collect(cls.__document__).update(
                                        {"token": token, "sys_key": sys_key, "event": event, "remote_ip": remote_ip}, **{"expire": result['expire']})
                                except Exception as e:
                                    return False, e
                        return True, result
                    else:
                        try:
                            state, msg= cls.del_token(token,event=event,sys_key=sys_key,remote_ip=remote_ip)
                        except Exception as e:
                            logging.info(e.args)
                        return False, "token has expire."
                else:
                    if result['is_use']==0:
                        cls.use_token(token, event=event, sys_key=sys_key, remote_ip=remote_ip)
                        return True, result
                    else:
                        return False, "token has used."   
            else:
                return False, "can not found token."
        except Exception as e:
            return False, e

    @classmethod
    def get_token(cls, query: dict, event=None, sys_key=cfg.SERVICE_KEY, remote_ip=None):
        """
        @classmethod
        获取缓存中的token信息
        
        Args:
            query (dict): 查询条件字典
            event (Optional[str]): 事件类型，可选
            sys_key (Optional[str]): 系统密钥，默认为配置中的SERVICE_KEY
            remote_ip (Optional[str]): 远程IP地址，可选
        
        Returns:
            Tuple[Optional[str], Optional[Union[str, Exception]]]: 
                返回(token, expire)元组，查询失败时返回(None, None)或(None, 异常对象)
        """
        try:
            if event:
                query['event'] = event
            if sys_key:
                query['sys_key'] = sys_key
            if remote_ip:
                query['remote_ip'] = remote_ip
            result = WEB_CACHE.collect(cls.__document__).get(**query)
            if result:
                return result['token'], result['expire']
            else:
                return None, None
        except Exception as e:
            return None, e

    @classmethod
    def del_token(cls, token, event=None, sys_key=cfg.SERVICE_KEY, remote_ip=None):
        """
        @classmethod
        删除指定token的缓存记录
        
        Args:
            token (str): 要删除的token
            event (str, optional): 关联事件名. Defaults to None.
            sys_key (str, optional): 系统标识. Defaults to cfg.SERVICE_KEY.
            remote_ip (str, optional): 远程IP地址. Defaults to None.
        
        Returns:
            tuple: (操作状态, 结果/异常)
                成功时返回 (True, 删除结果)
                失败时返回 (False, 异常对象)
        """
        try:
            if remote_ip:
                return True, WEB_CACHE.collect(cls.__document__).remove(**{"token": token, "sys_key": sys_key, "event": event, "remote_ip": remote_ip})
            else:
                return True, WEB_CACHE.collect(cls.__document__).remove(**{"token": token, "sys_key": sys_key, "event": event})
        except Exception as e:
            return False, e

    @classmethod
    def update_token(cls, token, expire, event=None, sys_key=cfg.SERVICE_KEY, remote_ip=None):
        """
        更新令牌缓存
        
        Args:
            token (str): 需要更新的令牌
            expire (int): 过期时间(秒)
            event (str, optional): 关联事件. 默认为None
            sys_key (str, optional): 系统密钥. 默认为配置中的SERVICE_KEY
            remote_ip (str, optional): 远程IP地址. 默认为None
        
        Returns:
            tuple: (是否成功, 结果/异常)
                成功时返回 (True, 更新结果)
                失败时返回 (False, 异常对象)
        """
        try:
            if remote_ip:
                return True, WEB_CACHE.collect(cls.__document__).update({"token": token, "sys_key": sys_key, "event": event, "remote_ip": remote_ip}, **{"expire": expire})
            else:
                return True, WEB_CACHE.collect(cls.__document__).update({"token": token, "sys_key": sys_key, "event": event}, **{"expire": expire})
        except Exception as e:
            return False, e

    @classmethod
    def use_token(cls, token, event= None, sys_key= cfg.SERVICE_KEY, remote_ip=None):
        """
        @classmethod
        使用并更新令牌状态
        
        Args:
            token (str): 要使用的令牌
            event (Any, optional): 关联事件，默认为None
            sys_key (str, optional): 系统标识，默认为配置的服务密钥
            remote_ip (str, optional): 远程IP地址，默认为None
        
        Returns:
            tuple: (是否成功, 更新结果或异常)
                   - 成功时返回 (True, 更新操作结果)
                   - 失败时返回 (False, 异常对象)
        """
        try:
            if remote_ip:
                return True, WEB_CACHE.collect(cls.__document__).update({"token": token, "sys_key": sys_key, "event": event, "remote_ip": remote_ip}, **{"is_use":1})
            else:
                return True, WEB_CACHE.collect(cls.__document__).update({"token": token, "sys_key": sys_key, "event": event}, **{"is_use":1})
        except Exception as e:
            return False, e

    @classmethod
    def get_union_field(cls, token, event=None, sys_key=cfg.SERVICE_KEY, remote_ip=None):
        """
        根据token、事件和系统密钥获取联合字段
        
        Args:
            token (str): 用户token
            event (str, optional): 事件名称. 默认为None
            sys_key (str, optional): 系统密钥. 默认为配置中的SERVICE_KEY
            remote_ip (str, optional): 远程IP地址. 默认为None
        
        Returns:
            tuple: (union_field, status) 
                - union_field: 获取到的联合字段，若token过期或出错则为None
                - status: 状态信息("success"/"token has expire"/"sys error")
        
        Raises:
            无显式抛出异常，内部错误会返回错误状态
        """
        try:
            if remote_ip:
                result = WEB_CACHE.collect(
                    (cls.__document__).get(
                        **{
                            "token": token, 
                            "sys_key": sys_key, 
                            "event": event, 
                            "remote_ip": remote_ip
                        }
                    )
                )
            else:
                result = WEB_CACHE.collect(
                    (cls.__document__).get(
                        **{
                            "token": token, 
                            "sys_key": sys_key, 
                            "event": event
                        }
                    )
                )
            if result["expire"] > datetime.now():
                return result["union_field"], "success"
            else:
                return None, "token has expire."
        except Exception as e:
            return None, "sys error."
